﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security;
using System.Windows.Forms;
using Aurora.DataAccess;
using Aurora.Domain;
using Aurora.Infrastructure;
using ComponentFactory.Krypton.Toolkit;

namespace Aurora.Core.ViewForms
{
    public partial class frmAddEdit : KryptonForm
    {
        private readonly IRepository _repository;
        
        /// <summary>
        /// Список сущностей, добавленных пользователем.
        /// </summary>
        private readonly IList<DomainObject> _addedEntities;

        /// <summary>
        /// Объект-сущность, предназначенный для редактирования.
        /// </summary>
        private readonly DomainObject _entityToEdit;

        /// <summary>
        /// Изменялось ли содержимое контекста;
        /// </summary>
        private bool _wasChanged;

        #region Constructors
        
        private frmAddEdit(){}

        /// <summary>
        /// Создает новый экземпляр формы.
        /// </summary>
        public frmAddEdit(IRepository repository)
        {
            _repository = repository;
            _addedEntities = new List<DomainObject>();

            InitializeComponent();
        }

        /// <summary>
        /// Конструктор, открывающий форму для редактирования.
        /// </summary>
        /// <param name="unityContainer"></param>
        /// <param name="repository"></param>
        /// <param name="card">Редактируемый объект</param>
        public frmAddEdit( IRepository repository, ClientCard card)
            : this(repository)
        {
            _entityToEdit = card;
            tabMainAdd.SelectedTabPage = tabCard;

            tbFirstNameAdd.Text = card.FirstName;
            tbInitialsAdd.Text = card.Initials;
            tbLastNameAdd.Text = card.LastName;
            dtBirthDayAdd.Value = card.BirthDay;
            tbAddressAdd.Text = card.Address;
        }

        /// <summary>
        /// Конструктор, открывающий форму для редактирования.
        /// </summary>
        /// <param name="unityContainer"></param>
        /// <param name="repository"></param>
        /// <param name="disease">Редактируемый объект</param>
        public frmAddEdit(IRepository repository, Disease disease)
            : this(repository)
        {
            _entityToEdit = disease;
            tabMainAdd.SelectedTabPage = tabDisease;

            tbDiseaseNameAdd.Text = disease.Name;
            tbDiseaseCathegoryAdd.Text = disease.Cathegory; ///TODO: Change to dropdownlists.
            tbDiseaseInfoAdd.Text = disease.Info;
        }

        /// <summary>
        /// Конструктор, открывающий форму для редактирования.
        /// </summary>
        /// <param name="unityContainer"></param>
        /// <param name="repository"></param>
        /// <param name="doctor">Редактируемый объект</param>
        public frmAddEdit(IRepository repository, Doctor doctor)
            : this(repository)
        {
            _entityToEdit = doctor;
            tabMainAdd.SelectedTabPage = tabDoctor;

            tbDoctorNameAdd.Text = doctor.Name;
            tbDoctorPostAdd.Text = doctor.Post;
            tbDoctorInfoAdd.Text = doctor.Info;
        }

        /// <summary>
        /// Конструктор, открывающий форму для редактирования.
        /// </summary>
        /// <param name="unityContainer"></param>
        /// <param name="repository"></param>
        /// <param name="service">Редактируемый объект</param>
        public frmAddEdit(IRepository repository, Service service)
            : this(repository)
        {
            _entityToEdit = service;
            tabMainAdd.SelectedTabPage = tabService;

            tbServiceNameAdd.Text = service.Name;
            tbServicePriceAdd.Text = service.Price.ToString();
            tbServiceInfoAdd.Text = service.Info;
        }
        #endregion

        /// <summary>
        /// Добавление объекта-сущности к контексту.
        /// </summary>
        /// <param name="entity">Объект-сущность</param>
        private void AddObject(DomainObject entity)
        {
            try
            {
                _wasChanged = true;

                if(_entityToEdit==null)
                {
                    _addedEntities.Add(entity);
                }
                else
                {
                    entity.SetId(_entityToEdit.Id);
                    _repository.Update(_entityToEdit, entity);

                    btnDone_Click(this, null);
                }
            }
            catch (ValidationException exception)
            {
                validationWarningToolTip.Show(exception.Message, this, 250, 175, 1000);
            }
            catch(OutOfMemoryException)
            {
                SaveOrNotToSave(Messenger.ShowYesNoQuestion("В системе заканчивается свободная память. Сохранить внесенные изменения в базу данных?"));
            }

            foreach (var x in
                    tabMainAdd.SelectedTabPage.Controls.Cast<Control>().
                    Where(x => x.GetType() == typeof (KryptonTextBox) || x.GetType() == typeof (TextBox)))
            {
                x.ResetText();
            }
        }

        /// <summary>
        /// Выбор опций сохранения в зависимости от результата отображаемого диалога.
        /// </summary>
        /// <param name="result"></param>
        private void SaveOrNotToSave(DialogResult result)
        {
            switch (result)
            {
                case DialogResult.Yes:
                    {
                        //Если список добавленных сущностей не пуст, то добавляем их все в репозиторий.
                        if(_addedEntities.Count != 0)
                        {
                            foreach (var domainObject in _addedEntities)
                            {
                                _repository.Insert(domainObject);
                            }
                        }

                        //Сохраняем изменения
                        if(_repository.SubmitChanges())
                            Messenger.ShowExclamation("Изменения сохранены в базу данных");
                        break;
                    }
                case DialogResult.No:
                    {
                        //Откатываем изменения
                        if (_repository.RejectChanges())
                            Messenger.ShowExclamation("Выполнен откат изменений");
                        break;
                    }
                case DialogResult.Cancel:
                    {
                        return;
                    }
            }
        }

        /// <summary>
        /// Проверка вводимых данных на валидность
        /// </summary>
        private void tb_KeyUp(object sender, KeyEventArgs e)
        {
            try
            {
                var textBox = (KryptonTextBox)sender;
                textBox.Text = TextProcessor.RusChar(textBox.Text);
            }
            catch (Exception)
            {
                Messenger.ShowErrorMessage("Ошибка применения регулярного выражения",
                                           "Сбой при выполнении программы. Перезапустите приложение или попробуйте повторить ваши действия.");
            }
        }

        private void btnCardAdd_Click(object sender, EventArgs e)
        {
            try
            {                
                AddObject(ClientCard.Create(tbFirstNameAdd.Text, 
                                            tbInitialsAdd.Text, 
                                            tbLastNameAdd.Text, 
                                            dtBirthDayAdd.Value.Date,
                                            tbAddressAdd.Text));
            }
            catch (Exception exception)
            {
                Messenger.ShowErrorMessage("Ошибка добавления объекта к контексту",
                                           exception.Message);
            }

        }

        private void btnDiseaseAdd_Click(object sender, EventArgs e)
        {
            try
            {
                AddObject(Disease.Create(tbDiseaseNameAdd.Text, 
                                         tbDiseaseInfoAdd.Text, 
                                         tbDiseaseCathegoryAdd.Text));
            }
            catch (Exception exception)
            {
                Messenger.ShowErrorMessage("Ошибка добавления объекта к контексту",
                                           exception.Message);               
            }
        }

        private void btnDoctorAdd_Click(object sender, EventArgs e)
        {
            try
            {
                AddObject(Doctor.Create(tbDoctorNameAdd.Text, 
                                        tbDoctorPostAdd.Text, 
                                        tbDoctorInfoAdd.Text));
            }
            catch (Exception exception)
            {
                Messenger.ShowErrorMessage("Ошибка добавления объекта к контексту",
                                           exception.Message);
            }
        }
        
        private void btnSeviceAdd_Click(object sender, EventArgs e)
        {
            try
            {
                AddObject(Service.Create(tbServiceNameAdd.Text,
                                          tbServiceInfoAdd.Text,
                                          Double.Parse(tbServicePriceAdd.Text)));
            }
            catch (Exception exception)
            {
                Messenger.ShowErrorMessage("Ошибка добавления объекта к контексту",
                                           exception.Message);
            }
        }

       private void btnDone_Click(object sender, EventArgs e)
        {
            if (_wasChanged)
            {
                var result = Messenger.ShowAcceptDeclineChangesQuestion();

                SaveOrNotToSave(result);
            }

            Close(); 
        }
        
        private void btnCancel_Click(object sender, EventArgs e)
        {
            _repository.RejectChanges();
            Close();
        }

        private void frmAddEdit_Load(object sender, EventArgs e)
        {
            if (_entityToEdit == null)
            {
                return;
            }
            foreach (Binarymission.WinFormControls.TabControls.BinaryPowerTabPage tabPage in tabMainAdd.TabPages)
            {
                tabPage.Visible = tabPage.CurrentlySelected;
            }
        }
    }
}
